home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / emac16ds.zip / MINTFORM.ASM < prev    next >
Assembly Source File  |  1991-08-03  |  15KB  |  537 lines

  1. title    minform.asm: MINT string data structure manipulator.
  2. ;History:14,1
  3. ;Mon May 06 00:58:06 1991 experiment with sgap marker.
  4. ;Tue May 22 10:27:09 1990 skip readjustments when deleting last form
  5. ;Sat May 19 21:16:53 1990 Change available space computation in define_form
  6. ;Tue Sep 12 23:49:09 1989 Add the find_string entry point.
  7. ;10-01-88 14:45:52 make get_mint_space return four numbers.
  8. ;12-06-87 00:51:14 finish adding 256K of mint space.
  9. ;12-06-87 00:26:46 start adding support for 256K of mint space.
  10. ;11-16-87 23:18:00 call new_buffer from init_forms.
  11.     page    ,132
  12.  
  13.     .xlist
  14.     include emacs.def
  15.     include    mintform.def
  16.     include    mint.def
  17.     .list
  18.  
  19. comment \
  20.  
  21. The forms:
  22.  
  23.     Forms are laid out as a linear list of forms.  formStore points to the
  24. beginning, and [topbot] points to the end.  The most recently defined forms are
  25. placed at the beginning of the list.  The forms consists of three elements: a
  26. header, the name, and the data.  The header contains the link to the next
  27. form, the length of the name, the length of the data, and the form pointer
  28. (which is always <= the length of the data).  The form structure is defined in
  29. the file 'mintform.def'.
  30.     When a form is to be looked up in form storage, the form is first
  31. hashed.  Then the form is looked up in the list of hash links.  A linear search
  32. is performed for all the forms that hash to that value.
  33.  
  34.     formhash is the hashing table for form names.  It is a list of
  35. pointers to forms.  Each form, in turn, has a pointer to the next form
  36. whose name hashes to the same entry in formhash. To add a new form, we
  37. must add the name to the proper place in the table.  To delete a form, the
  38. form name must be removed from formhash.  Their links in formhash and each
  39. of the forms must be updated, then the remaining forms get moved up in
  40. memory.
  41.  
  42.     Also, whenever a form gets looked up, it is placed at the head of
  43. the chain of hash pointers.  The assumption is that it will be looked up
  44. again shortly.
  45.  
  46. From: zardoz!sivs!hdasch@uunet.UU.NET (Hugh Daschbach)
  47.  
  48. Russ,
  49.  
  50. Thanks again for freemacs.  I find it invaluable.  I thought you
  51. might be interested in the following.  I pass it along for your
  52. information and review.
  53.  
  54. I recently wondered where all the time is spent in the next-buffer
  55. and previous-buffer services.  I rigged up a quick and dirty profiler
  56. and found that roughly 20% of the time, the program was executing
  57. code in delete_form.  This surprised me.  I considered modifying the
  58. form allocation and deallocation routines to see if I could reduce
  59. the overhead of deleting forms.  Before doing this, however, I found
  60. two simple modifications reduced this overhead.
  61.  
  62. The first is a change to find_form.  I noticed that find_form
  63. used form_struc.data_length instead of form_struc.form_length to
  64. determine if there is enough space to redefine an existing form.
  65. Using form_length (adjusted by name_length and size form_struc)
  66. reduced CPU utilization of delete_form from 20% to 5% in
  67. next-buffer/previous-buffer operations.
  68.  
  69. For the second change, I skip the hash table and form buffer space
  70. adjustments if the form being deleted is the last form in the buffer.
  71. This reduce to CPU utilization of delete_form from 5% to 3% of
  72. next-buffer/previous-buffer operations.
  73.  
  74. The following are diffs of mintform.asm based on the 1.6a sources.
  75. I specifically disclaim ownership of these changes.  You can do anything
  76. you want with them.
  77.  
  78. [ Diffs installed && deleted ]
  79.  
  80. Just in case you are interested this is the profiler's report of
  81. CPU utilization of routines executing during a next-buffer or
  82. previous-buffer request after implementing these two modifications:
  83.  
  84.   20% GS_PRIM
  85.   16% DOS
  86.   13% LS_PRIM
  87.   10% BUFFER_CHECK
  88.    7% NEXT_FORM
  89.    6% SCAN_RPAR_SUB
  90.    3% DELETE_FORM
  91.    3% FIND_STRING
  92.    3% RETURN_ACTIVE
  93.    3% GETARG
  94.    2% FIND_FORM
  95.    1% TRACE_RESULT
  96.    0% TRACE_INVOKE
  97.  
  98. \
  99.  
  100.  
  101. formSeg    segment    byte public
  102.  
  103.     define_buffer    form_
  104.  
  105.     public    syntax_table
  106. syntax_table    dw    NIL
  107. ;don't put anything here.
  108. formhashsize    equ    256
  109. formhash    dw formhashsize dup(NIL)
  110.  
  111. formStore    label    byte
  112.  
  113.  
  114. formSeg    ends
  115.  
  116.  
  117. segmoffs    struc
  118. offs        dw    ?
  119. segm        dw    ?
  120. segmoffs    ends
  121.  
  122.  
  123. data    segment byte public
  124.  
  125.     public    syntax_seg
  126. syntax_seg    dw    formSeg        ;segment holding syntax table.
  127.  
  128. this_segment    dw    ?        ;points to next formSegments to get.
  129. this_form    dd    ?        ;current form while enumerating.
  130.  
  131.     public    formSeg0, formSeg1, formSeg2, formSeg3
  132. formSegments    label    word
  133. formSeg0    dw    ?
  134. formSeg1    dw    ?
  135. formSeg2    dw    ?
  136. formSeg3    dw    ?
  137.  
  138.     extrn    data_bottop: word
  139.  
  140. data    ends
  141.  
  142.  
  143. code    segment byte public
  144.  
  145.     assume cs:code
  146.  
  147.     extrn    buffer_free: near
  148.     extrn    new_buffer: near
  149.     extrn    put_number: near
  150.  
  151.     public    init_forms
  152. init_forms:
  153.     mov    cx,4
  154.     mov    bx,offset formSegments
  155. init_forms_0:
  156.     assume    ds:data, es:data
  157.     push    bx
  158.     push    cx
  159.     mov    cx,offset formStore
  160.     call    new_buffer
  161.     pop    cx
  162.     pop    bx
  163.     jc    init_forms_1
  164.     xchgdses
  165.     assume    ds:data, es:formSeg
  166.     mov    [bx],es                ;remember this form segment.
  167.     add    bx,2
  168.     push    cx
  169.     mov    di,offset syntax_table        ;null out the hash table.
  170.     xor    ax,ax
  171.     mov    cx,256 + 1
  172.     rep    stosw
  173.     mov    ax,offset formStore        ;->end of forms.
  174.     mov    form_topbot,ax
  175.     mov    form_bottop,ax
  176.     mov    form_botbot,ax
  177.     esdata
  178.     pop    cx
  179.     loop    init_forms_0
  180.     clc
  181. init_forms_1:
  182.     ret
  183.  
  184.  
  185.     public    get_mint_space
  186. get_mint_space:
  187. ;enter with di -> place to put numbers.
  188. ;return four numbers giving the bytes of mint space available,
  189. ;  di ->end of strings.
  190.     mov    dx,ds            ;start with ds.
  191.     mov    cx,4            ;do four segments.
  192. get_mint_space_1:
  193.     push    ds            ;get the next segment
  194.     mov    ds,dx
  195.     assume    ds:formseg
  196.     mov    dx,form_next_buffer
  197.     mov    ds,dx
  198.     mov    ax,form_bottop        ;get the free space for this buffer.
  199.     sub    ax,form_topbot
  200.     pop    ds
  201.     assume    ds:data
  202.  
  203.     push    dx
  204.     push    cx
  205.     mov    cx,0            ;use only as many digits as is needed.
  206.     mov    bx,10
  207.     call    put_number
  208.     mov    al,','            ;seperate them by commas.
  209.     stosb
  210.     pop    cx
  211.     pop    dx
  212.     loop    get_mint_space_1
  213.     ret
  214.  
  215.  
  216. ;first_form sets us up to enumerate the forms (in no particular order).
  217. ;  Returns es:bx ->next form, zr if there is no next form.  Do not assume
  218. ;  that es will remain the same from one call to the next.
  219.     public    first_form, next_form
  220. first_form:
  221.     assume    ds:data, es:data
  222.     mov    this_segment,offset formSegments
  223. next_segment:
  224.     assume    ds:data, es:nothing
  225.     mov    bx,this_segment
  226.     add    this_segment,2            ;postincrement to the next seg.
  227.     cmp    bx,offset formSegments + 4*2    ;last form segment?
  228.     jz    next_last            ;yes - we're done.
  229.     mov    ax,[bx]                ;get the formSegment.
  230.     mov    this_form.segm,ax
  231.     mov    this_form.offs,offset formStore    ;->beginning of forms.
  232. next_form:
  233.     les    bx,this_form
  234.     assume    es:formSeg
  235.     mov    ax,formSeg:[bx].form_length    ;postincrement to the next form.
  236.     add    this_form.offs,ax
  237.     cmp    bx,form_topbot            ;go if we have no more forms.
  238.     je    next_segment
  239. next_last:
  240.     ret
  241.  
  242.  
  243. ;enter with ds:bx -> a form.  Make that form be the syntax table.
  244.  
  245.     public    store_syntax_table
  246. store_syntax_table:
  247.     assume    ds:formSeg, es:data
  248.     mov    syntax_table,bx
  249.     mov    syntax_seg,ds
  250.     ret
  251.  
  252.  
  253. ;define a form.  Enter with:
  254. ;    si => name
  255. ;    cx = name length
  256. ;    di => data
  257. ;    dx = data length
  258. ;    bx = form pointer.
  259.  
  260.     public    define_form
  261. define_form:
  262.     assume    ds:data, es:data
  263.     push    bx            ;save the form pointer.
  264.     call    find_form        ;see if it already exists.
  265.     jc    define_form_1        ;it doesn't.
  266.     assume    es:formSeg
  267. ;check to see if the form is already big enough.
  268.     mov    bp,dx
  269.     and    bp,7fffh        ;get rid of the sgap marker.
  270.     mov    ax,formSeg:[bx].form_length
  271.     sub    ax,cx
  272.     sub    ax,(size form_struc)
  273.     cmp    ax,bp
  274.     jbe    define_form_3            ;it isn't.
  275.     pop    formSeg:[bx].form_pointer        ;set the form pointer.
  276.     mov    si,di                ;prepare to move the data.
  277.     lea    di,formSeg:[bx].name_offset    ;->name.
  278.     add    di,cx                ;->data.
  279.     mov    formSeg:[bx].data_length,dx    ;set the data length.
  280.     mov    cx,bp                ;copy the new data in.
  281.     movmem
  282.     esdata
  283.     ret
  284. define_form_3:
  285.     assume    es:formSeg
  286.     push    di            ;delete the form pointed to by es:bx
  287.     push    si
  288.     push    cx
  289.     call    delete_form
  290.     pop    cx
  291.     pop    si
  292.     pop    di
  293.     esdata
  294. define_form_1:
  295.     pop    bx        ;restore form pointer.
  296.     push    di
  297.     push    bx
  298.     push    si
  299.     push    cx
  300.     call    hash_func        ;exit with es:[bx]->hash entry.
  301.     assume    es:formSeg
  302.     mov    bp,dx
  303.     and    bp,7fffh        ;get rid of the sgap marker.
  304.     add    cx,(size form_struc)    ;compute amount of space needed.
  305.     add    cx,bp
  306.     push    cx            ;push the size
  307.     mov    ax,es
  308.     call    buffer_free
  309.     jc    define_form_2            ;go if we can't get enough mem.
  310.     mov    di,form_topbot
  311.     pop    formSeg:[di].form_length        ;get the total size. (pushed as cx)
  312.     pop    cx                ;we have to pop into cx, because we
  313.     mov    formSeg:[di].name_length,cx    ;  need it later for the movsb.
  314.     mov    formSeg:[di].data_length,dx
  315.     pop    si                ;restore ->name
  316.     pop    formSeg:[di].form_pointer
  317.     mov    ax,formSeg:[bx]            ;get current formhash
  318.     mov    formSeg:[bx],di            ;make formhash point to us.
  319.     mov    formSeg:[di].hash_link,ax        ;make us point to current formhash.
  320.     add    di,name_offset            ;lea    di,[di].name_offset
  321.     movmem
  322.     pop    si                ;restore ->data
  323.     mov    cx,bp
  324.     movmem
  325.     mov    form_topbot,di            ;remember the new end.
  326.     esdata
  327.     ret
  328. define_form_2:
  329.     call    nomem
  330.  
  331.  
  332. ;Find a form.  Enter with:
  333. ;    si -> name
  334. ;    cx = name length
  335. ;Preserve di
  336. ;Exit with:
  337. ;    nc if form found, es:bx -> form
  338. ;    cy if form not found, es=data
  339.     public    find_form
  340. find_form:
  341.     assume    ds:data, es:data
  342.     push    dx
  343.     push    di
  344.     call    hash_func
  345.     assume    es:formSeg
  346.     push    bx            ;remember the formhash pointer.
  347.     xor    dx,dx
  348.     mov    bx,formSeg:[bx]        ;get ->first form that hashes here.
  349. find_form_1:
  350.     cmp    bx,NIL                ;end of list?
  351.     je    find_form_2            ;yes, we didn't find it.
  352.     cmp    cx,formSeg:[bx].name_length    ;lengths equal?
  353.     jne    find_form_3            ;no, go to next.
  354.     lea    di,formSeg:[bx].name_offset    ;compare names.
  355.     push    si
  356.     push    cx
  357.     rep    cmpsb
  358.     pop    cx
  359.     pop    si
  360.     jne    find_form_3        ;names not equal.
  361.     pop    di            ;restore the formhash pointer.
  362.     or    dx,dx            ;did we find it first?
  363.     je    find_form_4        ;yes - that's where we want it.
  364.     mov    ax,formSeg:[di]
  365.     mov    formSeg:[di],bx        ;make head -> found.
  366.     xchg    ax,formSeg:[bx].hash_link    ;make found -> old head.
  367.     mov    di,dx
  368.     mov    formSeg:[di].hash_link,ax    ;make pred(found) -> succ(found).
  369. find_form_4:
  370.     clc                ;found the form!
  371.     pop    di
  372.     pop    dx
  373.     ret
  374. find_form_3:
  375.     assume    es:formSeg
  376.     mov    dx,bx
  377.     mov    bx,formSeg:[bx].hash_link
  378.     jmp    find_form_1
  379. find_form_2:
  380.     pop    bx        ;restore the formhash pointer.
  381.     esdata
  382.     stc            ;didn't find the form!
  383.     pop    di
  384.     pop    dx
  385.     ret
  386.  
  387.  
  388. ;delete a form.  Enter with:
  389. ;    es:bx=>form
  390.  
  391.     public    delete_form
  392. delete_form:
  393. ;delete the form from the hashing table.
  394.     assume    ds:data, es:formSeg
  395.     mov    di,bx            ;make a copy of the pointer to the form.
  396.     mov    cx,formSeg:[bx].name_length
  397.     lea    si,formSeg:[bx].name_offset
  398.     xchgdses
  399.     assume    ds:formSeg, es:data
  400.     call    hash_func
  401.     assume    es:formSeg
  402.     sub    bx,hash_link        ;pretend that formhash is a form itself.
  403. delete_form_1:
  404.     cmp    formSeg:[bx].hash_link,di    ;does this form point to us?
  405.     je    delete_form_2        ;yes.
  406.     mov    bx,formSeg:[bx].hash_link    ;no - go to the next form.
  407.     jmp    delete_form_1
  408. delete_form_2:
  409.     mov    ax,formSeg:[di].hash_link    ;unlink us from the list.
  410.     mov    formSeg:[bx].hash_link,ax
  411. ;check for deletion of the syntax table.
  412.     cmp    di,syntax_table
  413.     jne    delete_form_7
  414.     mov    syntax_table,NIL    ;if we're deleting it, put NIL in.
  415. delete_form_7:
  416.     mov    ax,di            ;if last form, skip readjustments
  417.     add    ax,formSeg:[di].form_length
  418.     cmp    ax,form_topbot
  419.     je    delete_form_8
  420. ;now adjust the hash links in formhash.
  421.     mov    ax,formSeg:[di].form_length
  422.     mov    bx,offset syntax_table
  423.     mov    cx,formhashsize+1    ;add one for the syntax table.
  424. delete_form_3:
  425.     cmp    formSeg:[bx],di        ;do we need to adjust this one?
  426.     jbe    delete_form_4        ;no.
  427.     sub    formSeg:[bx],ax        ;yes - do it.
  428. delete_form_4:
  429.     add    bx,2
  430.     loop    delete_form_3
  431. ;now adjust all the hash links in the forms.  Notice that we are adjusting
  432. ;  the hash link in the form we are about to delete, but it doesn't hurt.
  433. ;  We can also presume the existence of at least one form at this point.
  434.     mov    bx,offset formStore        ;->beginning of forms.
  435. delete_form_5:
  436.     cmp    formSeg:[bx].hash_link,di    ;do we need to adjust this one?
  437.     jbe    delete_form_6        ;no.
  438.     sub    formSeg:[bx].hash_link,ax    ;yes - do it.
  439. delete_form_6:
  440.     add    bx,formSeg:[bx].form_length    ;compute the form after this one.
  441.     cmp    bx,form_topbot            ;no forms after this one.
  442.     jb    delete_form_5
  443.     mov    si,di            ;now move every form after this one down.
  444.     add    si,ax
  445.     mov    cx,form_topbot
  446.     sub    cx,si
  447.     movmem
  448. delete_form_8:
  449.     mov    form_topbot,di        ;remember the new form_topbot.
  450.     dsdata
  451.     esdata
  452.     ret
  453.  
  454.  
  455. ;find the form whose name is given in arg1.  Return the form pointer in
  456. ;ds:si, and the number of bytes remaining in the form in cx.
  457.     public    find_arg1
  458. find_arg1:
  459.     mov    cx,1
  460. ;fall through to find_arg
  461.  
  462. ;find the form whose name is given in the argument specified in cx.  Return
  463. ;  the form pointer in ds:si, and the number of bytes remaining in the form in
  464. ;  cx, and the pointer to the form in bx.
  465.     public    find_arg
  466. find_arg:
  467.     assume    ds:data, es:data
  468.     call    getarg
  469.     public    find_string
  470. find_string:
  471.     call    find_form
  472.     jc    find_arg1_1            ;if form doesn't exist, exit.
  473.     xchgdses
  474.     assume    ds:formSeg, es:data
  475.     lea    si,formSeg:[bx].name_offset    ;make si => form.data
  476.     add    si,formSeg:[bx].name_length
  477.     add    si,formSeg:[bx].form_pointer
  478.     mov    cx,formSeg:[bx].data_length    ;make cx = number of bytes left.
  479.     and    cx,7fffh            ;get rid of sgap marker.
  480.     sub    cx,formSeg:[bx].form_pointer
  481.     clc                    ;remember that form was found.
  482. find_arg1_1:
  483.     ret
  484.  
  485.  
  486. hash_func:
  487. ;enter with si,cx ->name to be hashed.
  488. ;exit with entry into hash table in ds:bx
  489. ;preserve dl.
  490.     assume    ds:nothing
  491.     push    si
  492.     push    cx
  493.     xor    bx,bx            ;start with zero.
  494.     jcxz    hash_func_1
  495.     xor    ah,ah
  496. hash_func_2:
  497.     lodsb
  498.     add    bx,ax
  499.     loop    hash_func_2
  500. hash_func_1:
  501.     mov    al,bl            ;save the low byte
  502.     mov    bl,bh
  503.     mov    bh,0
  504.     and    bl,3            ;four segments = two bits.
  505.     add    bx,bx            ;we're accessing words.
  506.     mov    es,formSegments[bx]    ;get the correct segment.
  507.     mov    bl,al            ;get the low byte back.  No need to
  508.                     ;zero bh again.
  509.     add    bx,bx
  510.     add    bx,offset formhash
  511.     pop    cx
  512.     pop    si
  513.     ret
  514.  
  515.  
  516. ;Adjust the form pointer after building a value which affects the
  517. ;  form pointer.  The new form pointer is derived from the count
  518. ;  of characters left in cx.  The form is pointed to by bx.
  519.     public    return_form
  520. return_form:
  521.     assume    ds:formSeg, es:data
  522.     mov    ax,formSeg:[bx].data_length
  523.     and    ax,7fffh        ;remove sgap marker.
  524.     sub    ax,cx
  525.     mov    formSeg:[bx].form_pointer,ax
  526.     dsdata
  527.     jmp    return_tos
  528.  
  529.  
  530.     extrn    return_tos: near
  531.     extrn    getarg: near
  532.     extrn    nomem: near
  533. code    ends
  534.  
  535.     end
  536.  
  537.